import {
  CallerSourceType,
  CanvasBehaviorActionList,
  CanvasBehaviorActionType,
  CanvasBehaviorHistory,
  CanvasMethod,
  CanvasProperties,
  CanvasType,
  Edge,
  Node
} from './canvasType'
import { mainWindow } from '../..'
import { getPortByStylePort, parseHistoryAction, recordHistoryAction } from './canvasTool'

class CanvasStore {
  private canvas: CanvasType = {
    nodes: [],
    edges: [],
    canvasProperties: {
      background: '#f7f7f7',
      showGrid: true,
      gridColor: '#e0e0e0',
      selectedNodeStyle: 'rotate',
      selectedNodeStyleColor: '#0087dc',
      enableSnapline: false,
      lock: false
    }
  }

  private selectCells: string[] = []

  private history: CanvasBehaviorHistory[] = []

  get canvasHistory() {
    return this.history
  }
  set canvasHistory(data: CanvasBehaviorHistory[]) {
    this.history = data
  }

  // 获取画布
  public getCanvas(): CanvasType {
    // 返回画布
    return this.canvas
  }

  // 更新画布
  public setCanvas(data: CanvasType): CanvasType {
    this.canvas.nodes = data.nodes
    this.canvas.edges = data.edges
    return this.canvas
  }

  // 清空画布
  public clearCanvas(): boolean {
    this.canvas.nodes = []
    this.canvas.edges = []
    return true
  }

  // 获取节点
  public getNodes<K extends keyof Node>(key: K = 'id' as K, value: Node[K]): Node[] {
    const results = this.canvas.nodes.filter((n) => n?.[key] === value)
    return results
  }

  // 添加节点
  public addNodes(nodes: Node | Node[]): Node[] {
    const newNodes = Array.isArray(nodes) ? nodes : [nodes]

    newNodes.forEach((node) => {
      node.style = {
        ...node.style
      }
      this.canvas.nodes.push(node)
    })

    return newNodes
  }

  // 更新节点
  public updateNodes<K extends keyof Node>(
    // 更新节点，可以是单个节点或节点数组
    updateNodes:
      | (Pick<Node, 'id'> & Partial<Record<K, Node[K]>>)
      | (Pick<Node, 'id'> & Partial<Record<K, Node[K]>>)[]
  ): Node[] {
    // 如果更新节点是数组，则将其转换为数组
    const needUpdateNodes = Array.isArray(updateNodes) ? updateNodes : [updateNodes]
    // 存储成功更新的节点
    const updatedNodes: Node[] = []
    for (const update of needUpdateNodes) {
      const node = this.canvas.nodes.find((n) => n.id === update.id)
      if (!node) continue
      for (const key in update) {
        if (key !== 'id' && key in node) {
          if (typeof update[key as K] === 'object' && update[key as K] !== null) {
            // 递归合并对象，保留未被更新的属性
            Object.assign((node as any)[key], update[key as K])
          } else {
            ;(node as any)[key] = update[key as K]
          }
        }
      }

      updatedNodes.push(node) // 将成功更新的节点添加到结果数组
    }

    return updatedNodes
  }

  // 节点移动
  public moveNode(id: string, x: number, y: number): Node | null {
    const node = this.canvas.nodes.find((n) => n.id === id)
    if (!node) return null
    node.x = Number(x)
    node.y = Number(y)
    return node
  }

  //节点移动原始位置记录
  public moveNodeRecord(data: { id: string; x: number; y: number }[]): any[] {
    return data
  }

  // 节点尺寸改变
  public changeNodeSize(id: string, width: number, height: number): Node | null {
    const node = this.canvas.nodes.find((n) => n.id === id)
    if (!node) return null
    node.width = Number(width)
    node.height = Number(height)
    return node
  }

  // 节点尺寸改变原始位置记录
  public changeNodeSizeRecord(data: { id: string; width: number; height: number }[]): any {
    return data
  }

  // 连接桩发生改变
  public changeNodePort(id: string): Node | null {
    const node = this.canvas.nodes.find((n) => n.id === id)
    if (!node) return null
    const temp = [
      node.style.portTop,
      node.style.portBottom,
      node.style.portLeft,
      node.style.portRight
    ]
    const ports = getPortByStylePort(temp)
    node.ports = ports
    return node
  }

  // 删除节点
  public deleteNodes(ids: string | string[]): Node[] {
    // 如果是单个 ID，转换为数组
    const newIds = Array.isArray(ids) ? ids : [ids]

    const deletedNodes: Node[] = []

    for (const id of newIds) {
      const index = this.canvas.nodes.findIndex((n) => n.id === id)
      if (index === -1) continue // 如果未找到节点，跳过
      deletedNodes.push(this.canvas.nodes.splice(index, 1)[0]) // 删除节点并加入结果数组
    }

    return deletedNodes
  }

  // 添加边
  public addEdges(edges: Edge | Edge[]): Edge[] {
    const newEdges = Array.isArray(edges) ? edges : [edges]

    const resultEdges = [] as Edge[]

    for (const edge of newEdges) {
      //先判断是否有重复的连线
      const existEdge = this.canvas.edges.find(
        (n) =>
          n.sourceId === edge.sourceId &&
          n.sourcePortId === edge.sourcePortId &&
          n.targetId === edge.targetId &&
          n.targetPortId === edge.targetPortId
      )
      if (!existEdge) {
        resultEdges.push(edge)
        this.canvas.edges.push(edge)
      }
    }

    return resultEdges
  }

  // 查找边
  public getEdges<K extends keyof Edge>(key: K = 'id' as K, value: Edge[K]): Edge[] {
    const results = this.canvas.edges.filter((n) => n?.[key] === value)
    return results
  }

  // 更新边
  public updateEdges<K extends keyof Edge>( // 更新节点，可以是单个节点或节点数组
    updateEdges:
      | (Pick<Edge, 'id'> & Partial<Record<K, Edge[K]>>)
      | (Pick<Edge, 'id'> & Partial<Record<K, Edge[K]>>)[]
  ): Edge[] {
    // 如果更新节点是数组，则将其转换为数组
    const needUpdateEdges = Array.isArray(updateEdges) ? updateEdges : [updateEdges]

    // 存储成功更新的节点
    const updatedEdges: Edge[] = []
    for (const update of needUpdateEdges) {
      const edge = this.canvas.edges.find((n) => n.id === update.id)
      if (!edge) continue
      for (const key in update) {
        if (key !== 'id' && key in edge) {
          if (typeof update[key as K] === 'object' && update[key as K] !== null) {
            // 递归合并对象，保留未被更新的属性
            Object.assign((edge as any)[key], update[key as K])
          } else {
            ;(edge as any)[key] = update[key as K]
          }
        }
      }

      updatedEdges.push(edge) // 将成功更新的节点添加到结果数组
    }

    return updatedEdges
  }

  // 删除边
  public deleteEdges(ids: string | string[]): Edge[] {
    const newIds = Array.isArray(ids) ? ids : [ids]

    const deletedEdges: Edge[] = []

    for (const id of newIds) {
      const index = this.canvas.edges.findIndex((n) => n.id === id)
      if (index === -1) continue // 如果未找到节点，跳过
      deletedEdges.push(this.canvas.edges.splice(index, 1)[0]) // 删除节点并加入结果数组
    }

    return deletedEdges
  }

  //获取画布属性
  public getCanvasProperties(): CanvasProperties {
    return this.canvas.canvasProperties
  }

  //改变画布属性
  public setCanvasProperties(properties: CanvasProperties): CanvasProperties {
    const keys = Object.keys(properties)
    for (const key of keys) {
      //判断key是否在canvasProperties中
      if (key in this.canvas.canvasProperties) {
        this.canvas.canvasProperties[key] = properties[key]
      }
    }

    return this.canvas.canvasProperties
  }

  //选择节点或边
  public selectNodesOrEdges(nodesOrEdges: string | string[]): string | string[] {
    this.selectCells = Array.isArray(nodesOrEdges) ? nodesOrEdges : [nodesOrEdges]
    return nodesOrEdges
  }

  //获取选中的节点或边
  public getSelectedNodesOrEdges(): string[] {
    return this.selectCells
  }

  //读取历史记录
  public readHistory(): void {
    parseHistoryAction()
  }

  //执行方法
  public executeMethod<M extends CanvasMethod>(
    methodName: M,
    callerSource: CallerSourceType,
    isBroadcast: boolean,
    record: boolean = true,
    ...args: Parameters<this[M]>
  ): ReturnType<this[M]> {
    const method = this[methodName] as Function
    const result = method.apply(this, args)

    if (isBroadcast) {
      this.broadcastEvent({
        methodName,
        callerSource,
        result
      })
    }

    if (record) {
      if (CanvasBehaviorActionList.includes(methodName as CanvasBehaviorActionType)) {
        recordHistoryAction(methodName as CanvasBehaviorActionType, result)
      }
    }

    return result
  }

  //广播事件
  public broadcastEvent(payload: any): void {
    mainWindow.webContents.send('canvasData', payload)
  }
}

export default new CanvasStore()
